#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <unordered_map>
#include <sstream>
#include <fstream>
#include <functional>
#include <strings.h>
#include "Log.hpp"

static const std::string sep = "\r\n";
static const std::string header_sep = ": ";
static const std::string wwwroot = "wwwroot";
static const std::string homepage = "index.html";
static const std::string httpversion = "HTTP/1.0";
static const std::string space = " ";
static const std::string filesuffixsep = ".";
static const std::string args_sep = "?";


class HttpRequest;
class HttpResponse;

using func_t = std::function<std::shared_ptr<HttpResponse>(std::shared_ptr<HttpRequest>)>;

// http 内容，要根据目标要访问的 资源的文件后缀，区分清楚文件的类型，同时Content-Typed告诉浏览器，我们的response的正文的类型
//  构建http request请求
class HttpRequest
{
private:
    // 提取一行信息
    std::string GetOneLine(std::string &reqstr)
    {
        if (reqstr.empty())
            return reqstr;
        auto pos = reqstr.find(sep);
        if (pos == std::string::npos)
            return std::string();

        // 得到以\r\n分割的一行字符串
        std::string line = reqstr.substr(0, pos);
        // 将截取到的字符串去除
        reqstr.erase(0, pos + sep.size());
        // 这里做特殊处理，如果遇到了空行
        return line.empty() ? sep : line;
    }

    bool PaserHeaderHelper(const std::string &line, std::string *k, std::string *v)
    {
        auto pos = line.find(header_sep);
        if (pos == std::string::npos)
            return false;
        *k = line.substr(0, pos);
        *v = line.substr(pos + header_sep.size());
        return true;
    }

public:
    HttpRequest() : _blank_line(sep), _path(wwwroot)
    {
    }
    // 序列化
    void Serialize()
    {
    }
    // 反序列化
    void Derialize(std::string &reqstr)
    {
        _req_line = GetOneLine(reqstr);
        while (true)
        {
            std::string line = GetOneLine(reqstr);
            if (line.empty())
                break;
            else if (line == sep) // 读到空行，后面的全是正文
            {
                _req_text = reqstr;
                break;
            }
            else
            {
                _req_header.emplace_back(line);
            }
        }
        ParseReqLine();
        ParesHeader();
    }

    // 打印测试接口
    void Print()
    {
        std::cout << "===" << _req_line << std::endl;
        for (auto &header : _req_header)
        {
            std::cout << "***" << header << std::endl;
        }
        std::cout << _blank_line << std::endl;
        std::cout << _req_text << std::endl;

        std::cout << "-----------------------------------------------------------" << std::endl;
        std::cout << "method ###" << _method << std::endl;
        std::cout << "url ###" << _url << std::endl;
        std::cout << "path ###" << _path << std::endl;
        std::cout << "version ###" << _version << std::endl;
        for (auto &header : _headers)
        {
            std::cout << "@@@ " << header.first << " - " << header.second << std::endl;
        }
    }
    bool ParseReqLine()
    {
        if (_req_line.empty())
            return false;
        // 按照空格进行分离
        std::stringstream ss(_req_line);
        ss >> _method >> _url >> _version;

        if (strcasecmp("get", _method.c_str()) == 0) // 忽略大小写
        {
            //  /index.html?user=zhangsan&password=123456
            // 分离参数
            auto pos = _url.find(args_sep);
            if (pos != std::string::npos)
            {
                LOG(INFO, "change begin, url: %s\n", _url.c_str());

                _args = _url.substr(pos + args_sep.size());
                _url.resize(pos);
                LOG(INFO, "change down, url: %s, _args: %s\n", _url.c_str(), _args.c_str());
            }
        }
        _path += _url;

        LOG(DEBUG, "url: %s\n", _url.c_str());

        // 判断请求的是否是/,如果是默认加上index.html
        if (_path[_path.size() - 1] == '/')
        {
            _path += homepage;
        }

        auto pos = _path.rfind(filesuffixsep);
        if (pos == std::string::npos)
        {
            _suffix = ".unknown";
        }
        else
        {
            _suffix = _path.substr(pos);
        }

        LOG(INFO, "client want get %s, suffix: %s\n", _path.c_str(), _suffix.c_str());
        return true;
    }
    bool ParesHeader()
    {
        for (auto &header : _req_header)
        {
            std::string k, v;
            if (!PaserHeaderHelper(header, &k, &v))
                continue;
            _headers.insert(std::make_pair(k, v));
        }
        LOG(INFO, "get ParesHeader succes\n");
        return true;
    }
    std::string Path()
    {
        return _path;
    }

    std::string Suffix()
    {
        return _suffix;
    }

    bool IsExec()
    {
        return !_args.empty() || !_req_text.empty();
    }

    std::string Args()
    {
        return _args;
    }

    std::string Text()
    {
        return _req_text;
    }

    std::string Method()
    {
        return _method;
    }
    ~HttpRequest()
    {
    }

private:
    // 原始协议
    std::string _req_line;                // 请求行
    std::vector<std::string> _req_header; // 请求报头
    std::string _blank_line;              // 空行
    std::string _req_text;                // 请求正文

    // 期望协议，将其key/vlue形式化
    // 这三个从请求行来
    std::string _method;
    std::string _url;
    std::string _args; // get方法中的参数
    std::string _path; // 访问资源的路径，虽然有了url但是他是非标准化的，所以这里还要单独的将url转化为path
    std::string _version;
    std::string _suffix; // 获取文件后缀
    // 这行从请求报文来
    std::unordered_map<std::string, std::string> _headers;
};

class HttpResponse
{
public:
    HttpResponse() : _version(httpversion), _blank_line(sep)
    {
    }
    ~HttpResponse()
    {
    }
    // 添加状态行
    void AddStatusLine(int code, const std::string &desc)
    {
        _code = code;
        _desc = desc; // 后面做优化
    }
    void AddHeander(const std::string &k, const std::string &v)
    {
        LOG(INFO, "AddHeander: %s->%s\n", k.c_str(), v.c_str());
        _headers[k] = v;
    }
    void AddText(const std::string text)
    {
        _resp_text = text;
    }
    std::string Serialize()
    {
        // 状态行
        _status_line = _version + space + std::to_string(_code) + space + _desc + sep;
        // 响应报文
        for (auto &header : _headers)
        {
            _resp_header.emplace_back(header.first + header_sep + header.second + sep);
        }

        // 序列化
        std::string response = _status_line;
        for (auto &header : _resp_header)
        {
            response += header;
        }
        // 添加空行
        response += sep;
        // 添加正文
        response += _resp_text;
        return response;
    }

private:
    // 构建应答的必要字段
    std::string _version;                                  // 版本
    int _code;                                             // 状态码
    std::string _desc;                                     // 状态描述
    std::unordered_map<std::string, std::string> _headers; // 响应报头

    // 应答的结构化字段
    std::string _status_line;              // 请求行
    std::vector<std::string> _resp_header; // 响应报头
    std::string _blank_line;               // 空行
    std::string _resp_text;                // 响应正文
};

class Factory
{
public:
    static std::shared_ptr<HttpRequest> BuildHttpRequest()
    {
        return std::make_shared<HttpRequest>();
    }

    static std::shared_ptr<HttpResponse> BuildHttpResponse()
    {
        return std::make_shared<HttpResponse>();
    }
};

// 构建http response响应
class HttpServer
{
public:
    HttpServer()
    {
        _mime_type.insert(std::make_pair(".html", "text/html"));
        _mime_type.insert(std::make_pair(".css", "text/css"));
        _mime_type.insert(std::make_pair(".js", "application/x-javascript"));
        _mime_type.insert(std::make_pair(".png", "image/png"));
        _mime_type.insert(std::make_pair(".jpg", "image/jpeg"));
        _mime_type.insert(std::make_pair(".unknown", "text/html"));

        _code_to_desc.insert(std::make_pair(100, "Continue"));
        _code_to_desc.insert(std::make_pair(200, "OK"));
        _code_to_desc.insert(std::make_pair(301, "Moved Permanently"));
        _code_to_desc.insert(std::make_pair(302, "Found "));
        _code_to_desc.insert(std::make_pair(404, "Not Found"));
        _code_to_desc.insert(std::make_pair(500, "Internal ServerError"));
    }

    std::string ReadFileContent(const std::string &path, int *size)
    {
        // 一定要按照二进制的方式打开
        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
            return std::string();

        // 首先获取文件大小
        in.seekg(0, in.end); // 将偏移量设置到文件结尾
        int filesize = in.tellg();
        in.seekg(0, in.beg); // 将偏移量恢复

        std::string content;
        content.resize(filesize);
        in.read((char *)content.c_str(), filesize);
        in.close();
        *size = filesize;
        return content;
    }

    void AddHeader(const std::string functionname, func_t f)
    {
        std::string key = wwwroot + functionname;
        std::cout << key << std::endl;
        _funcs[key] = f;
    }
    std::string HandlerHttpServer(std::string req)
    {
#ifdef TEST

        std::cout << "------------------------" << std::endl;
        std::cout << req;

        // 这里我们添加一些应答——这里后期解释为什么这样做
        std::string response = "HTTP/1.0 200 OK\r\n"; // 报头
        response += "\r\n";                           // 空行
        response += "<html><body><h1>hello world<h1><body><html>";
        return response;

#else
        std::cout << "------------------------" << std::endl;
        std::cout << req << std::endl;

        auto request = Factory::BuildHttpRequest();
        request->Derialize(req);
        // auto response = Factory::BuildHttpResponse();
        // std::string newurl = "https://www.qq.com/";
        // // request->Print();
        // int code = 0;
        // if (request->Path() == "wwwroot/redir")
        // {
        //     code = 302;
        //     response->AddStatusLine(code, _code_to_desc[code]);
        //     response->AddHeander("Location", newurl);
        // }
        if (request->IsExec())
        {
            LOG(DEBUG,"begin login\n");
            
            auto response = _funcs[request->Path()](request);
            LOG(DEBUG,"begin Serialize\n");

            return response->Serialize();
        }
        else
        {
            auto response = Factory::BuildHttpResponse();
            int code = 200;
            int contentsize = 0;
            std::string text = ReadFileContent(request->Path(), &contentsize);
            if (text.empty())
            {
                code = 404;
                response->AddStatusLine(code, _code_to_desc[code]);
                std::string text404 = ReadFileContent("wwwroot/404.html", &contentsize);
                response->AddHeander("Content-Length", std::to_string(contentsize));
                response->AddHeander("Content-Type", _mime_type[".html"]);
                response->AddText(text404);
            }
            else
            {
                std::string suffix = request->Suffix();
                response->AddStatusLine(code, _code_to_desc[code]);
                response->AddHeander("Content-Length", std::to_string(contentsize));
                response->AddText(text);
                response->AddHeander("Content-Type", _mime_type[suffix]);
            }
            return response->Serialize();

        }
        // std::string suffix = request->Suffix();
        // response->AddHeander("Content-Type", _mime_type[suffix]);

        // 找到资源
        // int contentsize = 0;
        // std::string text = ReadFileContent(request->Path(), &contentsize);

        // response->AddHeander("Content-Length", std::to_string(contentsize));
        // http协议已经给我们规定好了不同的文件后缀对应的Content-Typed
        // response->AddHeander("Content-Type", "text/html");
        // response->AddHeander("Location", "https://www.qq.com/");
        // response->AddText(text);

        // return response->Serialize();

#endif
    }

private:
    std::unordered_map<std::string, std::string> _mime_type;
    std::unordered_map<int, std::string> _code_to_desc;
    std::unordered_map<std::string, func_t> _funcs; 
};